在西門子PLC中使用SCL語言編程的技巧
前言: 兩年半前我就在工控網(wǎng)上發(fā)表了有關(guān)SCL編程的知識<<在s7300400型plc中使用高級語言編程>>,但發(fā)表完后,即使我自己都從沒有把任何使用SCL編寫的程序用到實際控制中,當(dāng)時的感覺是使用SCL編程到處受限,沒有STL語言靈活和強(qiáng)大。直到最近使用施耐德的Unity軟件編程,并使用這種已經(jīng)國際標(biāo)準(zhǔn)化的文本語言(等同于西門子的SCL語言),才體會到它的優(yōu)點:<1>、程序容易閱讀,便于診斷和維護(hù);<2>、程序容易在不同廠家之間的PLC之間轉(zhuǎn)換。西門子的STL語言是強(qiáng)大,但難于閱讀,編寫程序也需要異常小心,其最強(qiáng)大的可能是它的寄存器尋址(類似于一些計算機(jī)高級語言中的地址指針),SCL沒有這個功能,那就多費一些程序代碼來實現(xiàn)同樣的功能,程序是否優(yōu)秀更應(yīng)該看重程序的架構(gòu)和提高程序生產(chǎn)效率的標(biāo)準(zhǔn)化,好的PLC程序不應(yīng)該只有自己明白,而是讓更多的人明白。 在西門子PLC中使用SCL語言的場合一般是編寫標(biāo)準(zhǔn)功能塊FB,其編程方式和西門子的其他編程語言,如梯形圖Lad、語句表STL是完全不同的,同時為了實現(xiàn)程序的國際標(biāo)準(zhǔn)化,即為了方便的將程序代碼移植到不同廠家的PLC系統(tǒng)上,盡量不要在SCL中使用西門子獨有的功能塊。
1、 在FB塊中使用結(jié)構(gòu) 編寫FB塊的準(zhǔn)則,就是其使用的內(nèi)部變量盡量與外部隔離,除了像PLC的新啟動/重啟動標(biāo)志,以及一些方波/脈沖波等全局變量可以在FB塊中使用外,其他的任何全局變量都不應(yīng)該在FB內(nèi)部使用,即使是自定義結(jié)構(gòu)也應(yīng)該在FB中單獨定義,在FB塊中使用結(jié)構(gòu)應(yīng)該在靜態(tài)類型變量中定義,
如下: VAR// Static Variables IM:STRUCT//Data structure of Internal Flags H1_AFCountImp:BOOL:=False; // Aux Flag Counter Impulse H1_CountImp:BOOL:=False; // Counter Impulse H1_ELCountMV:BOOL:=False;// Endless Counter Maximum Value END_STRUCT;//other data structure … END_VAR 在使用這些結(jié)構(gòu)時,可以按照如下方式: IM. H1_CountImp:=Imp;
2、 在SCL中替代Set/Reset指令的方法 SCL中不存在Set/Reset指令,或者說也沒有必要使用。在SCL中,不使用排他條件Else的條件語句就是一個Set/Reset指令。
如下編程: IF THEN Variable name:=1; END_IF; 其等同于: (S)
若加上Else條件,如下: IF THEN Variable name:=1; ELSE Variable name:=0; END_IF; 則等同于: ( )
一條完整的包含置位和復(fù)位的語句可以使用如下方式編程:
IF THEN Variable name:=1; END_IF; IF THEN Variable name:=0; END_IF; 其等效于SR指令,若將上面的兩個條件語句的先后次序顛倒一下,則等效于RS指令。
3、 簡化程序指令 <1>、盡量使用賦值語句替代那些不用于SR/RS指令的BOOL型賦值條件語句,如下: IF fnAdd &(button=false) THEN pus1:=true; ELSE pus1:=false; END_IF; 其等效于pus1:= fnAdd &(NOT button),這樣使程序看起來更加簡潔和容易閱讀。
<2>、對于非BOOL型賦值語句則不能這如上簡化,而是可以通過SEL函數(shù)實現(xiàn): IF fnAdd &(button=false) THEN pus1:=value1; ELSE pus1:= value2; END_IF; 其等效于pus1:= SEL (G:= fnAdd &(button=false), IN0:= value2,IN1:= value1); 使用該函數(shù)時注意兩點: <1>、參數(shù)名不能省略; <2>、當(dāng)選擇條件G為TRUE時,選擇后一個參數(shù)值IN1,為FALSE時,選擇前一個參數(shù)值IN0,這點與計算機(jī)C語言等正好相反。 <3>、XOR指令有著比AND 和OR更為復(fù)雜的表達(dá),能使用XOR的地方應(yīng)該盡量使用 IF (condition1 AND (NOT condition2)) OR (condition2 AND ( NOT condition1)) THEN Result:=true; ELSE Result:=false; END_IF; 其等效于Result:= condition1 XOR condition2; XOR功能就是兩條件不同輸出TRUE,相同輸出FALSE
4、 脈沖沿檢測功能使用以下兩條語句替代脈沖上升沿檢測函數(shù),譬如檢測button_Input上升沿的代碼如下: Puls:=button_Input & (NOT button_Last); button_Last:= button_Input; 同樣的下降沿脈沖檢測如下: Puls:= ( NOT button_Input) & button_Last; button_Last:= button_Input;
5、 編寫脈沖發(fā)生器 波峰持續(xù)時間僅為一個PLC掃描周期的波形稱為脈沖波,而波峰持續(xù)時間大于或等于兩個PLC掃描周期的波形稱為方波,脈沖波可用于計數(shù)、定時,方波可用于控制信號燈的閃爍輸出,可以在西門子PLC的硬件配置中配置一個字節(jié)的各種時間的方波(波峰時間和波谷時間為1:1),假設(shè)"FP_1Sec" 為這個字節(jié)中1秒的方波,則: <1>、間隔1秒的脈沖波“Impls_1Sec” 如下編程: “Impls_1Sec” := "FP_1Sec" AND (NOT “Impls_1Sec_Aux”); “Impls_1Sec_Aux”:= "FP_1Sec" ; <2>、間隔10秒的脈沖波“Impls_10Sec” 如下編程: IF (“Impls_10Sec” ) THEN Count_ Actual:=0; “Impls_10Sec”:=0; ELSE IF (“Impls_1Sec” ) THEN Count_ Actual:= Count _ Actual +1; END_IF; “Impls_10Sec”:= Count_ Actual>=10; END_IF; Count_ Actual的初始值為0,同時當(dāng)系統(tǒng)新啟動時,也需將其設(shè)為零。間隔更長時間的脈沖波編程都可以按照上面的方式編程。
6、盡量使用編程計數(shù)功能來替代定時器功能,這樣使程序更可靠和易于閱讀假設(shè)Input_Condition為輸入,Output_Delay為通過定時處理后的輸出,Timer_Setpoint為時間設(shè)定點,Timer_Actual為當(dāng)前時間計數(shù)的實際值,“Impls_1Sec” 為系統(tǒng)編程產(chǎn)生的1秒脈沖。 <1>、在輸入條件滿足的情況下,延時輸出的定時器: IF (NOT Input_Condition) THEN Timer_Actual:= 0; Output_Delay:= 0; ELSE IF (“Impls_1Sec” AND NOT Output_Delay) THEN Timer_ Actual:= Timer_ Actual +1; END_IF; Output_Delay:= Timer_Actual >= Timer_Setpoint; END_IF;
<2>、有記憶的延時輸出定時器,即在延時過程中,若輸入條件終止,不影響延時,這種 定時器必須使用其它的信號復(fù)位。 IF Input_Condition THEN Output_Aux:=1; END_IF; IF (NOT Output_Aux) THEN Timer_Actual:= 0; Output_Delay:=0; ELSE IF (“Impls_1Sec” AND NOT Output_Delay) THEN Timer_ Actual:= Timer_ Actual +1; END_IF; Output_Delay:= Timer_Actual >= Timer_Setpoint; END_IF; 若想終止Output_Delay的輸出,必須在后面追加一條條件語句,用于復(fù)位Output_Aux
<3>、立即輸出,延時斷開的定時器 IF Input_Condition THEN Timer_Actual:= 0; Output_Aux:= 0; Output_Delay:=1; //立即輸出 ELSE IF (“Impls_1Sec” AND NOT Output_Aux) THEN Timer_ Actual:= Timer_ Actual +1; END_IF; Output_Aux:= Timer_Actual >= Timer_Setpoint; END_IF; IF Output_Aux THEN Output_Delay:=0;//延時斷開 END_IF;
<4>、在檢測到一個上升沿脈沖后,立即輸出,并開始計時,在 時間到達(dá)后斷開。 IF Input_Condition THEN Output_Aux:=1; END_IF; IF (NOT Output_Aux) THEN Timer_Actual:= 0; Timer_Arrived := 0; ELSE IF (NOT Timer_ Arrived AND “Impls_1Sec” ) THEN Timer_Actual:= Timer_Actual +1; END_IF; Timer_ Arrived := Timer_Actual >= Timer_Setpoint; END_IF; IF Timer_ Arrived THEN Output_Aux:=0; END_IF; Output_Delay:= Output_Aux;
通過以上的編程方式可以實現(xiàn)任何定時器功能,而代碼卻可以為不同的PLC系統(tǒng)所使用。
7、使用編程計數(shù)功能來替代計數(shù)器在SCL語言中使用計數(shù)功能是最為簡單的,其關(guān)鍵是必須首先對輸入進(jìn)行脈沖檢測假設(shè)Input_Imp為輸入脈沖,CountImp為輸入脈沖檢測,Counter為計數(shù)值,F(xiàn)actor為計數(shù)因子(更詳細(xì)點就是每來一次脈沖,計數(shù)值增加多少)。 (*----- Create Impulse (Impulse Evaluation) -----------------------------------------------------*) CountImp:= Input_Imp AND (NOT CountImp_Old); CountImp_Old:= Input_Imp; (*----- Counter ---------------------------------------------------------------------------------*) IF CountImp THEN Counter:= Counter+Factor; END_IF; 一個完整的計數(shù)程序應(yīng)該還有計數(shù)器復(fù)位功能以及計數(shù)值上限檢測條件(以防止計數(shù)值溢出)。
8、 新故障/新警告的檢測 一個完整的FB塊應(yīng)該能夠檢測故障/警告,以及新故障/新警告,假設(shè)Input1, Input2… Inputn對應(yīng)故障的輸入(有信號表示OK),F(xiàn)ault1, Fault2… Faultn對應(yīng)故障位,NFault1, NFault2…NFaultn對應(yīng)新故障位,F(xiàn)lt和NFlt分別對應(yīng)綜合的故障和新故障,Ackn對應(yīng)故障應(yīng)答輸入,為常開點,Mute對應(yīng)新故障消除輸入(或者稱為蜂鳴器沉寂),為常開點: Fault1:= NOT Input1 OR (Fault1 AND NOT Ackn); NFault1:= Fault1 AND (Mute OR NFault1); Fault2:= NOT Input2 OR (Fault2 AND NOT Ackn); NFault2:= Fault2 AND (Mute OR NFault2); … Flt := Fault1 OR Fault2 OR Faultn NFlt :=(Fault1 AND NOT NFault1) OR (Fault2 AND NOT NFault2) OR (Faultn AND NOT NFaultn) NFlt就是最終的新故障輸出指示,新警告的檢測與之類似。
9、字中取位 字中取位有兩種方式,一種是通過西門子所特有的字取位方式實現(xiàn),一種是通過計算機(jī)編程的標(biāo)準(zhǔn)方式實現(xiàn),假設(shè)Input_Word為輸入?yún)?shù),Word類型,W0,W1,…W15為位變量。 <1>、通過西門子的M變量實現(xiàn): Temp_Aux:=MW[10]; MW[10]:=Input_Word; W0:=M[11,0]; W1:=M[11,1]; W2:=M[11,2]; W3:=M[11,3]; W4:=M[11,4]; W5:=M[11,5]; W6:=M[11,6]; W7:=M[11,7]; W8:=M[10,0]; W9:=M[10,1]; W10:=M[10,2]; W11:=M[10,3]; W12:=M[10,4]; W13:=M[10,5]; W14:=M[10,6]; W15:=M[10,7]; MW[10]:=Temp_Aux;
<2>、通過標(biāo)準(zhǔn)編程實現(xiàn) w0:=(Input_Word & 16#1)=16#1; w1:=(Input_Word & 16#2)=16#2; w2:=(Input_Word & 16#4)=16#4; w3:=(Input_Word & 16#8)=16#8; w4:=(Input_Word & 16#10)=16#10; w5:=(Input_Word & 16#20)=16#20; w6:=(Input_Word & 16#40)=16#40; w7:=(Input_Word & 16#80)=16#80; w8:=(Input_Word & 16#100)=16#100; w9:=(Input_Word & 16#200)=16#200; w10:=(Input_Word & 16#400)=16#400; w11:=(Input_Word & 16#800)=16#800; w12:=(Input_Word & 16#1000)=16#1000; w13:=(Input_Word & 16#2000)=16#2000; w14:=(Input_Word & 16#4000)=16#4000; w15:=(Input_Word & 16#8000)=16#8000;
使用方式1會更加簡單和容易理解一些,但方式2具有更加寬廣的應(yīng)用場合,更加標(biāo)準(zhǔn)化,即使是當(dāng)今的計算機(jī)編程在取位操作時也類似于上面的編程。字取位的場合,一般用于總線數(shù)據(jù)(譬如變頻器的狀態(tài)數(shù)據(jù)),則可能是字/整數(shù),此時就需要用到上面的編程。 10、將位組合成字 相當(dāng)于“字中取位”的反向操作,這也有兩種方法,一種方法是使用M變量,類似于“字中取位”的方式 <1>,另一種也是標(biāo)準(zhǔn)編程,假設(shè)Output_Word為輸出參數(shù),Word類型,W0,W1,…W15為位變量。 <1>、通過西門子的M變量實現(xiàn): Temp_Aux:=MW[10]; M[11,0] := W0; M[11,1] := W1; M[11,2] := W2; M[11,3] := W3; M[11,4] := W4; M[11,5] := W5; M[11,6] := W6; M[11,7] := W7; M[10,0] := W8; M[10,1] := W9; M[10,2] := W10; M[10,3] := W11; M[10,4] := W12; M[10,5] := W13; M[10,6] := W14; M[10,7] := W15; Output_Word:=MW[10]; MW[10]:=Temp_Aux; <2>、通過標(biāo)準(zhǔn)編程實現(xiàn) IF W0 THEN Output_Word:=Output_Word OR 16#1; ELSE Output_Word:=Output_Word AND (NOT 16#1);END_IF; IF W1 THEN Output_Word:=Output_Word OR 16#2; ELSE Output_Word:=Output_Word AND (NOT 16#2);END_IF; IF W2 THEN Output_Word:=Output_Word OR 16#4; ELSE Output_Word:=Output_Word AND (NOT 16#4); END_IF; IF W3 THEN Output_Word:=Output_Word OR 16#8; ELSE Output_Word:=Output_Word AND (NOT 16#8); END_IF; IF W4 THEN Output_Word:=Output_Word OR 16#10; ELSE Output_Word:=Output_Word AND (NOT 16#10); END_IF; IF W5 THEN Output_Word:=Output_Word OR 16#20; ELSE Output_Word:=Output_Word AND (NOT 16#20); END_IF; IF W6 THEN Output_Word:=Output_Word OR 16#40; ELSE Output_Word:=Output_Word AND (NOT 16#40); END_IF; IF W7 THEN Output_Word:=Output_Word OR 16#80; ELSE Output_Word:=Output_Word AND (NOT 16#80); END_IF; IF W8 THEN Output_Word:=Output_Word OR 16#100; ELSE Output_Word:=Output_Word AND (NOT 16#100); END_IF; IF W9 THEN Output_Word:=Output_Word OR 16#200; ELSE Output_Word:=Output_Word AND (NOT 16#200); END_IF; IF W10 THEN Output_Word:=Output_Word OR 16#400; ELSE Output_Word:=Output_Word AND (NOT 16#400); END_IF; IF W11 THEN Output_Word:=Output_Word OR 16#800; ELSE Output_Word:=Output_Word AND (NOT 16#800); END_IF; IF W12 THEN Output_Word:=Output_Word OR 16#1000; ELSE Output_Word:=Output_Word AND (NOT 16#1000); END_IF; IF W13 THEN Output_Word:=Output_Word OR 16#2000; ELSE Output_Word:=Output_Word AND (NOT 16#2000); END_IF; IF W14 THEN Output_Word:=Output_Word OR 16#4000; ELSE Output_Word:=Output_Word AND (NOT 16#4000); END_IF; IF W15 THEN Output_Word:=Output_Word OR 16#8000; ELSE Output_Word:=Output_Word AND (NOT 16#8000); END_IF; 同樣的,使用標(biāo)準(zhǔn)化編程會繁瑣一些,但有著很強(qiáng)的通用性,在總線通訊控制中,很多控制字(如變頻器)都是以字的形式傳遞,所以需要把一些BOOL數(shù)據(jù)合并到一個字中,可以采用上面的對字中的位進(jìn)行置位/復(fù)位操作的方式,但事實上使用時,控制命令可能只有啟動/停止和方向控制等,所以這是可以直接對輸出賦值,譬如當(dāng)我們知道16#0F對應(yīng)啟動命令和正傳時,可以直接使用如下賦值語句即可控制變頻器正向運轉(zhuǎn):Output_Word:= 16#0F,如需反向運轉(zhuǎn),則再賦另一個值即可,而不需要像上面那樣對字的每一位操作。 以上是我總結(jié)的一些使用技巧,其編程可能有更好的實現(xiàn)方式,歡迎來信探討。
提交
超越傳統(tǒng)直覺,MATLAB/Simulink助力重型機(jī)械的智能化轉(zhuǎn)型
新大陸自動識別精彩亮相2024華南國際工業(yè)博覽會
派拓網(wǎng)絡(luò)被Forrester評為XDR領(lǐng)域領(lǐng)導(dǎo)者
智能工控,存儲強(qiáng)基 | 海康威視帶來精彩主題演講
展會|Lubeworks路博流體供料系統(tǒng)精彩亮相AMTS展會